package query_understanding.common.nlp_toolkit;

import algorithm.config.HumanLanguage;
import algorithm.nlp.corenlp.TextAnnotator;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import edu.stanford.nlp.ling.CoreAnnotations;
import edu.stanford.nlp.ling.IndexedWord;
import edu.stanford.nlp.pipeline.Annotation;
import edu.stanford.nlp.pipeline.StanfordCoreNLP;
import edu.stanford.nlp.semgraph.SemanticGraph;
import edu.stanford.nlp.semgraph.SemanticGraphCoreAnnotations;
import edu.stanford.nlp.semgraph.SemanticGraphEdge;
import edu.stanford.nlp.trees.GrammaticalRelation;
import edu.stanford.nlp.trees.UniversalEnglishGrammaticalRelations;
import edu.stanford.nlp.util.CoreMap;
import javafx.util.Pair;
import knowlwdge_graph.knowledge_etl.relation_etl.RelationExtractor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * Created by julianzliu on 4/23/2017.
 */
public class DependencyParser {

    static final Logger logger = LoggerFactory.getLogger( DependencyParser.class );


    public static String[] subjRelations = {"nsubj", "nsubjpass"};
    public static Set<String> subjRelSet = new HashSet<>( Arrays.asList(subjRelations) );

    public static String[] objRelations = {"dobj"};
    public static Set<String> objRelSet = new HashSet<>( Arrays.asList(objRelations) );

    public static String[] aclRelations = {"acl:relcl", "acl"};
    public static Set<String> aclRelSet = new HashSet<>( Arrays.asList(aclRelations) );

    public static String[] nmodRelations = {"nmod", "nmod:to", "nmod:poss", "nmod:of" };
    public static Set<String> nmodRelSet = new HashSet<>( Arrays.asList(nmodRelations) );

    public static String[] apposRelations = {"appos"};
    public static Set<String> appRelSet = new HashSet<>( Arrays.asList(apposRelations) );

    public static String[] advRelations = {"advmod"};
    public static Set<String> advRelSet = new HashSet<>( Arrays.asList(advRelations) );


    public static String[] depRelations = {"dep"};
    public static Set<String> depRelSet = new HashSet<>( Arrays.asList(depRelations));

    public static String[] verbPos = {"VBP", "VBD"};

    public static String[] nounPos = {"NN", "NNS", "NNP", "NNPS"};

    public static String[] queryPos = {"WP"};
    public static Set<String> queryPosSet = new HashSet<>(Arrays.asList(queryPos));



    public static String[] beVerbs = {"be", "is", "was", "are", "am"};
    public static Set<String> beVerbsSet = new HashSet<>( Arrays.asList(beVerbs) );



    public static void extractNounsRelation( SemanticGraph dependencies, IndexedWord current, Set<SemanticGraphEdge> edgeVisited, Set<IndexedWord> wordIVsited ){
       // dependencies.getIncomingEdgesSorted()


    }



    /*
    从current节点出发， 抽取未使用的元素中，
    可能是知识库关系的元素
     */
    public static List< Pair<SemanticGraphEdge,IndexedWord> > extractLengthOneRelation(SemanticGraph dependencies, IndexedWord current, Set<IndexedWord> visited){
        List<SemanticGraphEdge> inEdges = dependencies.getIncomingEdgesSorted(current);
        List<SemanticGraphEdge> outEdges = dependencies.getOutEdgesSorted( current );

        List<Pair<SemanticGraphEdge, IndexedWord>> relations = new ArrayList<>();

        for(SemanticGraphEdge inEdge: inEdges){
            Pair<SemanticGraphEdge, IndexedWord> pair = extractRelationFromInEdge( inEdge );
            if(pair != null) relations.add( pair );
        }

        for(SemanticGraphEdge outEdge: outEdges){
            Pair<SemanticGraphEdge, IndexedWord> pair = extractRelationFromOutEdge( outEdge );
            if(pair != null) relations.add( pair );
        }
        return relations;
    }


    public static List< RelationPath > extractLengthTwoRelation(SemanticGraph dependencies, IndexedWord current, Set<IndexedWord> visited){
        List<RelationPath> relations = new ArrayList<>();
        Stack<Pair<SemanticGraphEdge, IndexedWord>> curpath = new Stack<>();
        deepFirstTraversal(dependencies, current, visited, relations, curpath);
        for(RelationPath relationPath: relations){
            relationPath.startNode = current;
        }
        return relations;
    }

    private static void deepFirstTraversal(SemanticGraph dependencies, IndexedWord current, Set<IndexedWord> visited,
                                    List<RelationPath> relations, Stack<Pair<SemanticGraphEdge, IndexedWord>> curpath){
        visited.add(current);
        System.out.println(current);

        List<SemanticGraphEdge> inEdgesSorted = dependencies.getIncomingEdgesSorted(current);
        for (SemanticGraphEdge edge : inEdgesSorted) {
            //GrammaticalRelation relation = edge.getRelation();
            IndexedWord source = edge.getSource();
            if(visited.contains(source))
                continue;
            Pair<SemanticGraphEdge, IndexedWord> pair = extractRelationFromInEdge( edge );
            if(pair != null){
                curpath.push( pair );
                RelationPath path = genRelationPath( curpath );
                relations.add(path);
                deepFirstTraversal(dependencies, source, visited, relations, curpath);
                curpath.pop( );
            }
        }

        List<SemanticGraphEdge> outEdgesSorted = dependencies.getOutEdgesSorted(current);
        for (SemanticGraphEdge edge : outEdgesSorted) {
            //GrammaticalRelation relation = edge.getRelation();
            IndexedWord target = edge.getTarget();
            if(visited.contains(target))
                continue;
            Pair<SemanticGraphEdge, IndexedWord> pair = extractRelationFromOutEdge( edge );
            if(pair != null){
                curpath.push( pair );
                RelationPath path = genRelationPath( curpath );
                relations.add(path);
                deepFirstTraversal(dependencies, target,  visited, relations, curpath);
                curpath.pop();
            }
        }
    }

    private static RelationPath genRelationPath(Stack<Pair<SemanticGraphEdge, IndexedWord>> stack){
        RelationPath relationPath = new RelationPath();
        relationPath.path = new ArrayList<>( stack );
        return relationPath;
    }




    /**********************************************************************************************************************************************/



    /***********************************************************************************************************************************************
     *
     * @param dependencies
     * @param current
     * @param visitedNodes
     * @param visitedEdges
     * @return
     */
    public static List<RelationTriplePath> extractAllPossiblePath(SemanticGraph dependencies, IndexedWord current, Set<IndexedWord> visitedNodes, Set<SemanticGraphEdge> visitedEdges){
        List<RelationTriplePath> relationTriplePaths = new ArrayList<>();
        Stack<RelationEdge.BaseRelation> curpath = new Stack<>();

        //dependencies.getNodeByWordPattern("Obama");

        deepFirstExtract(dependencies, current, visitedNodes, visitedEdges, relationTriplePaths, curpath);

        return relationTriplePaths;
    }


    private static void deepFirstExtract(SemanticGraph dependencies, IndexedWord current,
                                         Set<IndexedWord> visitedNodes, Set<SemanticGraphEdge> visitedEdges,
                                         List<RelationTriplePath> relations, Stack<RelationEdge.BaseRelation> curpath){
        System.out.println("\n\nCurrent = " + current);
        visitedNodes.add(current);
        /*
        current meas the linkPoint of BaseRelation
         */
        List<SemanticGraphEdge> inEdgesSorted = dependencies.getIncomingEdgesSorted(current);
        for (SemanticGraphEdge inEdge : inEdgesSorted) {
            IndexedWord source = inEdge.getSource();
            //if(visitedNodes.contains( source ) || visitedEdges.contains(inEdge)){
            if(visitedEdges.contains(inEdge)){
                logger.info("edge visited {}", inEdge);
                continue;
            }

            RelationEdge.BaseRelation extractRelation = extractRelationEdgeFromInEdge(dependencies, inEdge, visitedEdges, visitedNodes);
            if(extractRelation != null){
                curpath.push( extractRelation );
                RelationTriplePath gen_path = genRelationTriplePath( curpath );
                relations.add( gen_path );
                visitedNodes.add( extractRelation.relation);
                visitedNodes.add( extractRelation.otherSide);
                visitedEdges.add( extractRelation.inEdge);
                visitedEdges.add( extractRelation.outEdge );
                IndexedWord next = extractRelation.otherSide;
                deepFirstExtract(dependencies, next, visitedNodes, visitedEdges, relations, curpath);
                curpath.pop();
            }
        }

        List<SemanticGraphEdge> outEdgesSorted = dependencies.getOutEdgesSorted(current);
        for (SemanticGraphEdge outEdge : outEdgesSorted) {
            //GrammaticalRelation relation = edge.getRelation();
            IndexedWord target = outEdge.getTarget();
            //if(visitedNodes.contains(target) || visitedEdges.contains(outEdge)){
            if(visitedEdges.contains(outEdge)){
                logger.info("edge visited {}", outEdge);
                continue;
            }
            RelationEdge.BaseRelation extractRelation = extractRelationEdgeFromOutEdge(dependencies, outEdge, visitedEdges, visitedNodes);
            if(extractRelation != null){
                curpath.push( extractRelation );
                RelationTriplePath gen_path = genRelationTriplePath( curpath );
                relations.add( gen_path );
                visitedNodes.add( extractRelation.relation);
                visitedNodes.add( extractRelation.otherSide);
                visitedEdges.add( extractRelation.inEdge);
                visitedEdges.add( extractRelation.outEdge );
                IndexedWord next = extractRelation.otherSide;
                deepFirstExtract(dependencies, next, visitedNodes, visitedEdges, relations, curpath);
                curpath.pop();
            }
        }
    }

    private static RelationTriplePath genRelationTriplePath(Stack<RelationEdge.BaseRelation> stack){
        RelationTriplePath path = new RelationTriplePath();
        path.path = new ArrayList<>( stack );
        return path;
    }




    /*************************************************************************************
     *
     *        路径增长函数
     *
     **************************************************************************************/
    /*
    判断一条入边是否构成关系
     */
    private static RelationEdge.BaseRelation extractRelationEdgeFromInEdge(SemanticGraph dependencies,SemanticGraphEdge edge, Set<SemanticGraphEdge> edgeVisited, Set<IndexedWord> wordIVsited ){
        //Pair<SemanticGraphEdge, IndexedWord> pair = null;
        GrammaticalRelation relation = edge.getRelation();
        String relation_str = relation.getShortName();
        IndexedWord source = edge.getSource();
        IndexedWord target = edge.getTarget();
        //IndexedWord gov = edge.getGovernor();
        Double weight = edge.getWeight();
        logger.info("[In EDGE] edge = {}, relation_name = {}, relation = {}, source = {},  weight = {}, ", edge,relation_str, relation, source, weight);

        RelationEdge.BaseRelation relationEdge = null;
        /*********************************************************
         * 对于一个关系，总结其另外一端可能的关系
         * 构造三元组
         */

        /***********************
        主语开始搜寻 subj
         */
        if(relation == UniversalEnglishGrammaticalRelations.NOMINAL_SUBJECT || subjRelSet.contains( relation_str )){
            RelationEdge.VerbsRelation verbsRelation = new RelationEdge.VerbsRelation();
            verbsRelation.inEdge = edge;
            verbsRelation.linkPoint = target;
            //verbsRelation.subj = target;
            verbsRelation.relation = source;  //source可能是动词或者名词  who is wife of Obama?
            /*
            对于某些动词短语 ， 如 be from ，需要进一步搜索 dep  ...
            is -> dep -> from
             */
            System.out.println("[Source] word = " + source.word());
            if( beVerbsSet.contains( source.word() )){
                List<SemanticGraphEdge> outEdges = dependencies.getOutEdgesSorted(source);
                for(SemanticGraphEdge outEdge: outEdges){
                    GrammaticalRelation outRelation = outEdge.getRelation();
                    String out_relation_str = outRelation.getShortName();
                    // is -> dep -> from
                    if( depRelSet.contains(out_relation_str)){
                        IndexedWord targetObj = outEdge.getTarget();
                        verbsRelation.relation = targetObj;
                        source = targetObj;
                        System.out.println("[Source] changed, " + source);
                    }
                }
            }


            /*
            corenlp http://corenlp.run/
            对于句子 university where wife of Barack Obama graduated
            网站-》 acl 连接 -》 深度学习
            软件-》 dep 连接 -》 非深度学习
             */
            if(verbsRelation.otherSide == null){
                // try to find acl
                List<SemanticGraphEdge> inEdges = dependencies.getIncomingEdgesSorted(source);
                for(SemanticGraphEdge inEdge: inEdges){
                    GrammaticalRelation inRelation = inEdge.getRelation();
                    String in_relation_str = inRelation.getShortName();
                    // acl:relcl
                    if( aclRelSet.contains(in_relation_str)){
                        IndexedWord sourceObj = inEdge.getSource();
                        verbsRelation.otherSide = sourceObj;
                        verbsRelation.outEdge = inEdge;
                    }
                }
            }
            /*
            dep 连接, 通用依赖
             */
            if(verbsRelation.otherSide == null){
                // try to find dep
                List<SemanticGraphEdge> outEdges = dependencies.getOutEdgesSorted(source);
                for(SemanticGraphEdge outEdge: outEdges ){
                    GrammaticalRelation outRelation = outEdge.getRelation();
                    String out_relation_str = outRelation.getShortName();
                    // subj ->VBD -> obj  'who married Obama?'
                    if( "dep".equalsIgnoreCase(out_relation_str) ){
                        IndexedWord targetObj = outEdge.getTarget();
                        verbsRelation.otherSide = targetObj;
                        verbsRelation.outEdge = outEdge;
                    }
                }
            }

            if(verbsRelation.otherSide == null){
                // try to find obj
                List<SemanticGraphEdge> outEdges = dependencies.getOutEdgesSorted(source);
                for(SemanticGraphEdge outEdge: outEdges ){
                    GrammaticalRelation outRelation = outEdge.getRelation();
                    String out_relation_str = outRelation.getShortName();
                    // VBD -> obj  'who married Obama?'
                    if( objRelSet.contains(out_relation_str) ){
                        IndexedWord targetObj = outEdge.getTarget();
                        verbsRelation.otherSide = targetObj;
                        verbsRelation.outEdge = outEdge;
                    }
                    // VBD -> nmod  'who married to Obama'
                    if( nmodRelSet.contains( out_relation_str ) ){
                        IndexedWord targetObj = outEdge.getTarget();
                        verbsRelation.otherSide = targetObj;
                        verbsRelation.outEdge = outEdge;
                    }
                }
            }


            /*
            疑问句  where wife of Obama graduated from?
            subj -> VB -> admod -> where
             */
            if(verbsRelation.otherSide == null){
                // try to find obj
                List<SemanticGraphEdge> outEdges = dependencies.getOutEdgesSorted(source);
                for(SemanticGraphEdge outEdge: outEdges ){
                    GrammaticalRelation outRelation = outEdge.getRelation();
                    String out_relation_str = outRelation.getShortName();
                    // VBD ->  advmod ->    where wife of Obama graduated from?
                    if( advRelSet.contains(out_relation_str) ){
                        IndexedWord targetObj = outEdge.getTarget();
                        if(targetObj.tag().equalsIgnoreCase("WRB")){
                            verbsRelation.otherSide = targetObj;
                            verbsRelation.outEdge = outEdge;
                        }
                    }
                }
            }

            if(verbsRelation.otherSide == null){
                verbsRelation.otherSide = source;
                verbsRelation.outEdge = edge;
            }
            relationEdge = verbsRelation;
        }


        /**********************************
        从宾语开始搜寻  obj
        who killed Lincoln?
         */
        // dobj
        else if(relation == UniversalEnglishGrammaticalRelations.DIRECT_OBJECT || objRelSet.contains(relation_str)) {
            RelationEdge.VerbsRelation verbsRelation = new RelationEdge.VerbsRelation();
            verbsRelation.linkPoint = target;
            verbsRelation.inEdge = edge;
            //verbsRelation.subj = target;
            verbsRelation.relation = source; // source是动词
            /*
            acl  先找acl，再找subj/obj
             */
            if(verbsRelation.otherSide == null){
                // try to find acl
                List<SemanticGraphEdge> inEdges = dependencies.getIncomingEdgesSorted(source);
                for(SemanticGraphEdge inEdge: inEdges){
                    GrammaticalRelation inRelation = inEdge.getRelation();
                    String in_relation_str = inRelation.getShortName();
                    // acl:relcl
                    if( aclRelSet.contains(in_relation_str)){
                        IndexedWord sourceObj = inEdge.getSource();
                        verbsRelation.otherSide = sourceObj;
                        verbsRelation.outEdge = inEdge;
                    }
                }
            }
            if(verbsRelation.otherSide == null){
                // try to find subj
                List<SemanticGraphEdge> outEdges = dependencies.getOutEdgesSorted(source);
                for(SemanticGraphEdge outEdge: outEdges ){
                    GrammaticalRelation outRelation = outEdge.getRelation();
                    String out_relation_str = outRelation.getShortName();
                    // subj ->VBD -> obj  'who married Obama?'
                    if( subjRelSet.contains(out_relation_str) ){
                        IndexedWord targetObj = outEdge.getTarget();
                        verbsRelation.otherSide = targetObj;
                        verbsRelation.outEdge = outEdge;
                    }
                }
            }

            if(verbsRelation.otherSide == null){
                verbsRelation.otherSide = source;  //先设置为关系点
                verbsRelation.outEdge = edge;
            }
            relationEdge = verbsRelation;
        }




        /******************************
        名词性修饰语  nmod.
        其另外一端可能是 subj ， 或者 appos
         */
        else if(relation == UniversalEnglishGrammaticalRelations.NOMINAL_MODIFIER || nmodRelSet.contains( relation_str )){
            RelationEdge.NounsRelation nounsRelation = new RelationEdge.NounsRelation();
            nounsRelation.linkPoint = target;
            nounsRelation.inEdge = edge;
            nounsRelation.relation = source;  //名词
            // 出边 Michelle is wife of Obama.
            /*
            subj   -> Michelle is wife of Obama.
            appos  -> Michelle ,  wife of Obama.
             */
            if(nounsRelation.otherSide == null){
                // try to find suj
                List<SemanticGraphEdge> outEdges = dependencies.getOutEdgesSorted(source);
                for(SemanticGraphEdge outEdge: outEdges ){
                    GrammaticalRelation outRelation = outEdge.getRelation();
                    String out_relation_str = outRelation.getShortName();
                    // subj ->VBD -> obj  'who married Obama?'
                    if( subjRelSet.contains(out_relation_str)  || appRelSet.contains(out_relation_str) ){
                        IndexedWord targetObj = outEdge.getTarget();
                        nounsRelation.otherSide = targetObj;
                        nounsRelation.outEdge = outEdge;
                    }
                }

            }
            /*
            Obama's Brother Who Voted Trump
            不应该考虑另外的，下一步继续以brother处的变量节点往外搜索，能够以subj关联voted的
             */
            /*
            if(nounsRelation.otherSide == null){
                // try to find acl
                List<SemanticGraphEdge> outEdges = dependencies.getOutEdgesSorted(source);
                for(SemanticGraphEdge outEdge: outEdges){
                    GrammaticalRelation inRelation = outEdge.getRelation();
                    String in_relation_str = inRelation.getShortName();
                    // acl:relcl
                    if( aclRelSet.contains(in_relation_str)){
                        IndexedWord targetObj = outEdge.getTarget();
                        nounsRelation.otherSide = targetObj;
                        nounsRelation.outEdge = outEdge;
                    }
                }
            }
            */

            if(nounsRelation.otherSide == null){
                nounsRelation.otherSide = source;  //先设置为关系点
                nounsRelation.outEdge = edge;
            }
            relationEdge = nounsRelation;
        }





        if(relationEdge != null)
            logger.info("\n added relation {}", relationEdge.toString() );
        return relationEdge;
    }


    private static RelationEdge.BaseRelation extractRelationEdgeFromOutEdge(SemanticGraph dependencies,SemanticGraphEdge edge, Set<SemanticGraphEdge> edgeVisited, Set<IndexedWord> wordIVsited ) {
        //Pair<SemanticGraphEdge, IndexedWord> pair = null;
        GrammaticalRelation relation = edge.getRelation();
        String relation_str = relation.getShortName();
        IndexedWord source = edge.getSource();
        IndexedWord target = edge.getTarget();
        //IndexedWord gov = edge.getGovernor();
        Double weight = edge.getWeight();
        logger.info("[Out EDGE] edge = {}, relation_name = {}, relation = {}, source = {}, gov = {}, weight = {}, ", edge, relation_str, relation, source, weight);

        RelationEdge.BaseRelation relationEdge = null;

        /**************************
         * acl  主句的名词 -》 出边
         */
        if( aclRelSet.contains(relation_str) ){
            RelationEdge.VerbsRelation verbsRelation = new RelationEdge.VerbsRelation();
            verbsRelation.linkPoint = source;
            verbsRelation.inEdge = edge;
            //verbsRelation.subj = target;
            verbsRelation.relation = target; // source是名词，被从句修饰的名词
            if(verbsRelation.otherSide == null){
                // target 是动词
                // try to find subj or obj
                List<SemanticGraphEdge> outEdges = dependencies.getOutEdgesSorted(target);
                for(SemanticGraphEdge outEdge: outEdges ){
                    GrammaticalRelation outRelation = outEdge.getRelation();
                    String out_relation_str = outRelation.getShortName();
                    // acl -> [VBD, ..]  -> [subj, dobj]
                    if( subjRelSet.contains(out_relation_str) || objRelSet.contains(out_relation_str) ){
                        IndexedWord targetObj = outEdge.getTarget();
                        verbsRelation.otherSide = targetObj;
                        verbsRelation.outEdge = outEdge;
                    }
                }
            }
            if(verbsRelation.otherSide == null){
                verbsRelation.otherSide = target;  //先设置为关系点
                verbsRelation.outEdge = edge;
            }
            relationEdge = verbsRelation;
        }


        /**************************
         * app  名词 -》 解释
         * Michelle, wife of Obama
         */
        if( appRelSet.contains(relation_str) ){
            RelationEdge.VerbsRelation verbsRelation = new RelationEdge.VerbsRelation();
            verbsRelation.linkPoint = source;
            verbsRelation.inEdge = edge;
            //verbsRelation.subj = target;
            verbsRelation.relation = target; // source是名词，被从句修饰的名词
            if(verbsRelation.otherSide == null){
                // target 是nmod名词
                List<SemanticGraphEdge> outEdges = dependencies.getOutEdgesSorted(target);
                for(SemanticGraphEdge outEdge: outEdges ){
                    GrammaticalRelation outRelation = outEdge.getRelation();
                    String out_relation_str = outRelation.getShortName();
                    // acl -> [VBD, ..]  -> [subj, dobj]
                    if( nmodRelSet.contains(out_relation_str) ){
                        IndexedWord targetObj = outEdge.getTarget();
                        verbsRelation.otherSide = targetObj;
                        verbsRelation.outEdge = outEdge;
                    }
                }
            }
            if(verbsRelation.otherSide == null){
                verbsRelation.otherSide = target;  //先设置为关系点
                verbsRelation.outEdge = edge;
            }
            relationEdge = verbsRelation;
        }

        if(relationEdge != null)
            logger.info("\n added relation {}", relationEdge.toString() );

        return relationEdge;
    }





    /*****************************************************************************************************************************************
     * 以下为旧的废弃代码
     */

    /**************************************************************************************************/
    /*
    判断一条入边是否构成关系
     */
    private static Pair<SemanticGraphEdge,IndexedWord> extractRelationFromInEdge( SemanticGraphEdge edge ){
        Pair<SemanticGraphEdge, IndexedWord> pair = null;
        GrammaticalRelation relation = edge.getRelation();
        String relation_str = relation.getShortName();
        IndexedWord source = edge.getSource();
        IndexedWord gov = edge.getGovernor();
        Double weight = edge.getWeight();
        logger.info("[In EDGE] edge = {}, relation_name = {}, relation = {}, source = {}, gov = {}, weight = {}, ", edge,relation_str, relation, source, gov, weight);

        // nmod
        if(relation == UniversalEnglishGrammaticalRelations.NOMINAL_MODIFIER){
            pair = new Pair<>(edge, source);
        }
        // nmod：poss
        if(relation_str.equalsIgnoreCase("nmod") || relation_str.equalsIgnoreCase("nmod:poss") || relation_str.equalsIgnoreCase("nmod:of")){
            pair = new Pair<>(edge, source);
        }
        // nsubj
        if(relation == UniversalEnglishGrammaticalRelations.NOMINAL_SUBJECT){
            pair = new Pair<>(edge, source);
        }
        // dobj
        if(relation == UniversalEnglishGrammaticalRelations.DIRECT_OBJECT) {
            pair = new Pair<>(edge, source);
        }
        if(pair != null)
            logger.info("\n added relation {}, {}", pair.getKey(), pair.getValue());
        return pair;
    }

    /*
    判断一条出边是否构成关系
     */
    private static Pair<SemanticGraphEdge,IndexedWord> extractRelationFromOutEdge( SemanticGraphEdge edge ){
        Pair<SemanticGraphEdge, IndexedWord> pair = null;
        GrammaticalRelation relation = edge.getRelation();
        IndexedWord target = edge.getTarget();

        logger.info("[Out EDGE] edge = {}, relation = {}, target = {}", edge, relation, target);

        if(relation == UniversalEnglishGrammaticalRelations.APPOSITIONAL_MODIFIER){
            pair = new Pair<>(edge, target);
        }
        if(pair != null){
            logger.info("\n added relation {}, {}", pair.getKey(), pair.getValue());
            logger.debug("test wether debug output");
        }


        return pair;
    }


    /***********************************************************************************************************/
    /*
    http://stackoverflow.com/questions/31458201/how-to-create-a-grammaticalrelation-in-stanford-corenlp
     */
    public static void testRelatonMatcher(SemanticGraph dependencies, IndexedWord current){
        //GrammaticalRelation relation = new GrammaticalRelation();
        Set<IndexedWord> childs  = dependencies.getChildrenWithReln( current, UniversalEnglishGrammaticalRelations.NOMINAL_MODIFIER );
        Set<IndexedWord> parents = dependencies.getParentsWithReln(current  , UniversalEnglishGrammaticalRelations.NOMINAL_SUBJECT);

    }


    public static class RelationsExtractionTester{

        private StanfordCoreNLP pipeline;
        private ObjectMapper mapper;

        public RelationsExtractionTester(){
            Properties props = new Properties();
            //props.setProperty("annotators", "tokenize, ssplit, pos, lemma, ner, parse, dcoref");
            //props.setProperty("annotators", "tokenize, ssplit, pos, lemma, ner, parse");
            props.setProperty("annotators", "tokenize,ssplit,pos,lemma,ner,depparse");
            pipeline = new StanfordCoreNLP(props);
            mapper = new ObjectMapper();
        }


        public JsonNode testExtractRelations(String query,String start){

            ObjectNode sentRelations = this.mapper.createObjectNode();


            Set<IndexedWord> visitedNodes = new HashSet<>();
            Set<SemanticGraphEdge> visitedEdges = new HashSet<>();

            //TextAnnotator textAnnotator = new TextAnnotator(HumanLanguage.ENGLISH);
            //Annotation document = textAnnotator.getAnnotatedText(query);


            Annotation document = new Annotation(query);
            pipeline.annotate( document );
            pipeline.prettyPrint( document, System.out );

            List<CoreMap> sentences = document.get(CoreAnnotations.SentencesAnnotation.class);
            Integer sentIndex = 0;
            for (CoreMap sentence : sentences) {
                SemanticGraph dependencies = sentence.get(SemanticGraphCoreAnnotations.BasicDependenciesAnnotation.class);
                IndexedWord root = dependencies.getNodeByWordPattern( start );
                List<RelationTriplePath> relations = extractAllPossiblePath(dependencies, root, visitedNodes, visitedEdges);
                List<String> relations_str = printRelations( relations );
                String key = new Integer( sentence.hashCode() ).toString();
                ArrayNode array = this.mapper.createArrayNode();
                for(String str: relations_str)
                    array.add( str );
                sentRelations.put(key, array);
            }

            return sentRelations;
        }

        private List<String> printRelations(List<RelationTriplePath> relations){
            List<String> relations_str = new ArrayList<>();
            for(RelationTriplePath relationTriplePath:relations){
                System.out.println(relationTriplePath.toString());
                relations_str.add( relationTriplePath.toString() );
            }
            return relations_str;
        }

    }






    /******************************************************************************
     * MAIN
     */
    public static void main(String[] args){
        String query  = "university where wife of Barack Obama graduated.";
        query = "Obama's brother who voted Trump.";
        query = "where is Jamarcus Russell from?";
        //query = "where was Jamarcus Russell born?";
        //query = "who did Jamarcus Russell married to?";
        //testExtractRelations( query, "Russell" );

        RelationsExtractionTester tester = new RelationsExtractionTester();
        tester.testExtractRelations( query,  "Russell" );
    }


}
